perm filename PARSER.SAI[HAL,HE] blob sn#121120 filedate 1974-09-22 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00010 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00002 00002	BEGIN "parser"    COMMENT: An interpreter for parse tables 
C00004 00003	! Description of the machine
C00006 00004	! How to match left_hand sides
C00008 00005	! Evaluating labels
C00009 00006	! Saving and restoring the parsing environment
C00011 00007	! The stack of procedures
C00012 00008	! Reading the source program
C00013 00009	! Initialization phase
C00014 00010	! Parsing
C00018 ENDMK
C⊗;
BEGIN "parser"    COMMENT: An interpreter for parse tables 
			   translated from PL by PTRANS;
require "INIT[CSP,SYS]" source_file;
define oct(zzz) = ⊂ "'"&cvos(zzz LAND '7777) ⊃;
define state = ⊂ oct(pc)&"["&cvs(bytpos)&"]" ⊃;

! The files below are the tables created by PTRANS.SAI for the use
of the parser;

require "LAB" source_file;
require "EXEC" source_file;
require "TABLE" source_file;


integer pc, bytpos;  ! The program counter;

integer dummy, i;

! The parsing stack;

define maxstack = ⊂ 50 ⊃;
ref(entri) array stack[1:maxstack]; integer stacktop;

! The stack for procedures;

define maxproc = ⊂ 30 ⊃;
integer array programstack[1:maxproc]; integer  programdepth;

ref(entri)
var0, var1, var2, var3, var4, var5, var6, var7, var8, var9, 
var10, var11, var12, var13, var14, var15, var16, var17, var18, var19;
! Description of the machine;

SIMPLE integer PROCEDURE getword;
	BEGIN
	integer result;
	parsedebug(crlf&tab&"PC: "&state);
	result ← case bytpos of
		(production[pc] lsh -24,
		(production[pc] lsh -12) land '7777,
		production[pc] land '7777);
	if result land '4000  then
		result ← result lor '777777770000;
	parsedebug(". Table element: "&oct(result)&"(i.e. "&cvs(result)&")");
	bytpos ← bytpos +1; if bytpos = 3 then
		BEGIN
		pc ← pc + 1; bytpos ← 0
		END;
	return(result)
	END;

SIMPLE procedure jump(VALUE integer elemnum);
	BEGIN
	pc ← (elemnum + 2) div 3 ;
	bytpos ← (elemnum + 2) mod 3;
	parsedebug(crlf&tab&"Jump to "&oct(pc)&"["&cvs(bytpos)&"]")
	END;

! How to match left_hand sides;

BOOLEAN PROCEDURE coincide (VALUE integer howmany);
	BEGIN
	RECURSIVE BOOLEAN procedure match(VALUE integer elmnt, matchtype);
		BEGIN
		boolean result;
		parsedebug(crlf&"Trying to match "&oct(elmnt)&" and "&oct(matchtype));
		result ← (matchtype= 0) ∨ (matchtype = elmnt);
		if result then 
			BEGIN parsedebug("  MATCH");
			return(TRUE)
			END
		else if matchtype ≤ lowerclass ∨ matchtype ≥ upperclass then
			BEGIN
			parsedebug("  DON'T MATCH");
			return(FALSE)
			END
		else
			BEGIN
			integer hashval;
			parsedebug(" Second is class. Enter recursion");
			hashval ← elmnt mod 10;
			do
				BEGIN
				parsedebug(crlf&"Triple "&oct(hashval));
				if (hashclass[hashval] lsh -24) = elmnt 
				∧ match((hashclass[hashval] land '77770000) lsh -12,matchtype)
				then
					BEGIN parsedebug("  MEMBER");
					return(TRUE)
					END
				else
					hashval ← hashclass[hashval] LAND '7777
				END
			until hashval = 0;
			parsedebug(" NO MATCH");
			return(FALSE)
			END
		END;
	for i ← (stacktop - howmany + 1) step 1 until stacktop do
		if ¬match(entri:rtype[stack[i]],getword) then
			return(FALSE);
	return(TRUE)
	END;
! Evaluating labels;

SIMPLE integer PROCEDURE getlab( VALUE integer nummlab);
	BEGIN
	integer result;
	integer wor, pos;
	wor ← (nummlab + 2)  div 3; pos ← (nummlab + 2) mod 3;

	result ← case pos of
		(labels[wor] lsh -24,
			(labels[wor] lsh -12) land '7777,
				labels[wor] land '7777);

	parsedebug(crlf&tab&"Label "&oct(nummlab)&" is production word "&oct(result));
	return(result)
	END;
! Saving and restoring the parsing environment;

SIMPLE PROCEDURE save(VALUE integer index);

if index > 0 then
	case stacktop - index of
		BEGIN
			var0  ← stack[stacktop];
			var1  ← stack[stacktop - 1 ];
			var2  ← stack[stacktop - 2 ];
			var3  ← stack[stacktop - 3 ];
			var4  ← stack[stacktop - 4 ];
			var5  ← stack[stacktop - 5 ];
			var6  ← stack[stacktop - 6 ];
			var7  ← stack[stacktop - 7 ];
			var8  ← stack[stacktop - 8 ];
			var9  ← stack[stacktop - 9 ];
			var10 ← stack[stacktop - 10];
			var11 ← stack[stacktop - 11];
			var12 ← stack[stacktop - 12];
			var13 ← stack[stacktop - 13];
			var14 ← stack[stacktop - 14];
			var15 ← stack[stacktop - 15];
			var16 ← stack[stacktop - 16];
			var17 ← stack[stacktop - 17];
			var18 ← stack[stacktop - 18];
			var19 ← stack[stacktop - 19]
		END;


SIMPLE ref(entri) PROCEDURE getback(VALUE integer index);

BEGIN
if index > 0 then
	return (case (stacktop - index) of
		(var0, var1, var2, var3,var4,var5,var6,var7,var8));
!	 ,var9,	var10,var11,var12,var13,var14,var15,var16,var17,var18,var19));
! LINE ABOVE CAUSES PROBLEMS FOR THE COMPILER;
error("restore called with a negative argument");
END;
! The stack of procedures;

SIMPLE integer PROCEDURE popretaddr;
	! Pop stack and get return address;
	if (programdepth ← programdepth - 1) < 0 then
		error("Procedure stack underflow")
	else
		return(programstack[programdepth]);


! Push new return address;

define pushretaddr(newaddr) =  ⊂
			if (programdepth ← programdepth + 1) > maxproc then
				error("Procedure stack overflow")
			else
				programstack[programdepth] ← newaddr ⊃;
! Reading the source program;

SIMPLE PROCEDURE sscan(VALUE integer how_many);
	for i ← 1 step 1 until how_many do
		BEGIN
		lexan;
		stacktop ← stacktop + 1;
		if stacktop > maxstack then
			error("Parse stack overflow");
		if token = tidentifier ∨ token = tdoubledelim then
			stack[stacktop] ← new_id
		else
			BEGIN
			entri:rtype[stack[stacktop]] ← token;
			DATUM(entri:name [stack[stacktop]]) ← symb
			END
		END;
! Initialization phase;
outstr("HAL file? "); 
initscan(instrl(crlf),17,FALSE);

debugparse ← please_answer("Debugging the parser?");
for i ← firstres step 1 until lastres do
	BEGIN
	dummy ← searchinsert(resword[i]);
	entri:rtype[new_id] ← i
	END;

if please_answer("Want to follow the scanning token after token?") then
	debugmode ← TRUE;
pc ← 1; bytpos ← 0;
! Parsing;
do
	BEGIN "interp"
	integer prodexecnum, numsucc, numfail, proccode;
	integer leftnum,  rightnum;
	boolean failed; 

	parsedebug(crlf&crlf&"Trying production "&state);
	numfail ← getword;
	parsedebug("  FAILURE LABEL");
	if numfail = 0 then
		DONE "interp";
	leftnum ← getword;parsedebug("  NO. OF LEFT ELEMENTS");
	failed ←  (stacktop < leftnum) ∨ ¬ coincide(leftnum);
	while failed do
		BEGIN "fail"
		parsedebug(crlf&tab&" Failed.");
		if numfail < 0 then
			jump(-numfail)
		else
			jump(getlab(numfail));
		parsedebug(crlf&"Trying production "&state);
		numfail ← getword;
		if numfail = 0 then
			DONE "interp";
		parsedebug("  FAILURE LABEL");
		leftnum ← getword;parsedebug("  NO. OF LAST ELEMENTS");
		failed ← (stacktop < leftnum) ∨ ¬ coincide(leftnum)
		END;
	for i ← 1 step 1 until leftnum do
		save(i);
	rightnum ← getword;PARSEDEBUG("  NO. OF RIGHT ELEMENTS");
	stacktop ← stacktop - leftnum + rightnum;
	for i ← 1 step 1 until rightnum  do
		BEGIN "replace"
		integer rightel;
		if (rightel ← getword) > 0 then
			entri:rtype[stack[stacktop - rightnum + i]] ← rightel
		else if rightel < 0 then
			stack[stacktop -rightnum + i] ← getback(-i);
		parsedebug("  RIGHT ELEMENT")
		END;
	prodexecnum ← getword;parsedebug("  NO. OF EXEC ROUTINES");
	for i ← 1 step 1 until prodexecnum do
		BEGIN
		integer ii; ii ← getword; parsedebug("  EXEC ROUTINE");
		exec(ii)
		END;
	i ← getword; parsedebug("  NUMBER OF SCANS"); sscan(i);
	numsucc ← getword;parsedebug("  SUCCESS LABEL");
	if numsucc = 0 then
		numsucc ← 3*(pc - 1) + bytpos + 2
	else
		numsucc ← getlab(numsucc);
	proccode ← getword; parsedebug("  PROCEDURE CODE");
	if proccode > 0 then
		BEGIN
		pushretaddr(numsucc); jump(getlab(proccode))
		END
	else if proccode < 0 then
		jump(popretaddr)
	else
		jump(numsucc)
	END
until false;
! The normal exit is by way of DONE above, otherwise looping goes on.;
END